Conversation
When a publisher aborts a track with Error::App(code), the subscriber now correctly receives Error::App(code) instead of Error::Cancel. The fix has two parts: 1. Error::from_transport() checks stream_error() on transport errors to decode QUIC stream reset codes back into the original Error variant via the new from_code() method, instead of wrapping everything as Error::Transport. 2. Subscribers no longer collapse Error::Transport into Error::Cancel, so decoded errors like Error::App propagate to consumers. Also simplifies Error by removing inner data from Transport, Decode, Version, RequiredExtension, and BoundsExceeded variants, making the error type fully round-trippable through to_code()/from_code(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughThe PR refactors error representation and handling across the moq-lite crate: several Error variants (Transport, Decode, Version, RequiredExtension, BoundsExceeded) become unit-like, many new variants are added, and Error gains 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
rs/moq-lite/src/error.rs (1)
77-102:⚠️ Potential issue | 🟡 Minor
to_codecan overflow for largeAppvalues.
App(u32::MAX).to_code()computesu32::MAX + 64, which panics in debug builds and wraps in release builds. SinceApp(u32)is public, callers can construct any value. Consider either clamping/saturating or validating at construction time.Proposed fix: saturating arithmetic
- Self::App(app) => *app + 64, + Self::App(app) => app.saturating_add(64),Alternatively, you could cap
Appvalues infrom_codeor add a constructor that validatesapp < u32::MAX - 63.rs/moq-lite/src/coding/reader.rs (1)
92-110:⚠️ Potential issue | 🟠 Major
read_exactmay loop infinitely if the stream closes before the buffer is filled.The
RecvStream::read_bufmethod returnsResult<Option<usize>>, whereOk(None)signals EOF. On line 106, the result is only checked for errors via.map_err(Error::from_transport)?, butOk(None)is silently discarded and the loop continues. This causes an infinite loop if the stream closes prematurely. Theread_more()method (line 151) correctly handles this with a match statement that checks forOk(None).Proposed fix
while buf.has_remaining_mut() { - self.stream.read_buf(&mut buf).await.map_err(Error::from_transport)?; + match self.stream.read_buf(&mut buf).await { + Ok(Some(_)) => {} + Ok(None) => return Err(Error::Decode), + Err(e) => return Err(Error::from_transport(e)), + } }
- Change Error::App(u32) to Error::App(u16) to prevent overflow when encoding to wire format (code + 64). Out-of-range codes in from_code() now return ProtocolViolation instead of silently truncating. - Fix pre-existing infinite loop in read_exact when the stream closes before the buffer is filled. read_buf returning Ok(None) was silently ignored; now returns Error::Decode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roberte777
left a comment
There was a problem hiding this comment.
I think this looks good to me, basically what I came up with as well.
Integrate UnknownAlpn variant and Version enum refactor from main, keeping our simplified Error::Version (no inner data). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Fixes #936. When a publisher aborts a track with
Error::App(code), subscribers now correctly receiveError::App(code)instead ofError::Cancel.Error::from_transport()checksstream_error()on transport errors to decode QUIC stream reset codes back into the originalErrorvariant via the newfrom_code()method, instead of wrapping everything asError::TransportError::TransportintoError::Cancel, so decoded errors likeError::Apppropagate correctly to consumersErrorenum by removing inner data fromTransport,Decode,Version,RequiredExtension, andBoundsExceededvariants, making the error type fully round-trippable throughto_code()/from_code()Test plan
just checkpasses (compilation, tests, linting, formatting)track.abort(Error::App(42))→ subscriber receivesError::App(42)(notError::Cancel)🤖 Generated with Claude Code